﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;
using Gma.UserActivityMonitor;
using System.Data;
using System.Collections;

namespace AutoMouseClick
{
    class RunClick
    {
        private DataWareHouse dataWH;
        private bool runState = false;
        private bool refreshImage = false;
        private bool isPause = false;
        private bool isStop = false;
        private int idxTskTest = -1;
        private const int WAITCODE = -1;
        private const int WHEELCODE = -2;
        private const int MOUSEDRAPCODE = -3;
        private const int COLORCODE = -4;
        private const int CLICKCOLORCODE = -5;
        private const int UNCLICKCOLORCODE = -6;
        private const int UNCLICKBLACKLISTCODE = -7;
        private const int CLICKWHITELISTCODE = -8;
        private const int CLICKANDPASTELINKCODE = -9;
        private const int CLICKANDPASTEANDENTERLINKCODE = -10;
        private const int CLICKANDPASTEANDTABLINKCODE = -11;
        private const int VOTAN = -1;
        private bool isHaveSpecialTask = false;
        private TaskLevel4 specialTask = new TaskLevel4();
        private TaskLevel4 specialTaskAtTime = new TaskLevel4();
        private DateTime midTimeST = new DateTime();
        private DateTime endTimeST = new DateTime();
        private DateTime beginEstimate;
        private DateTime atTime = new DateTime();
        private bool midTimeCheckST = false;
        private bool endTimeCheckST = false;
        private bool atTimeCheckST = false;
        //private bool endTimeCheckST = false;
        private int minuteST;
        private int percentST;
        private bool midCheckST;
        private bool taskPass = false;
        TimeSpan excutiveTime;

        [StructLayout(LayoutKind.Sequential)]
        public struct COLORRGBA
        {
            public byte r;
            public byte g;
            public byte b;
            public byte a;
        }

        public RunClick(ref DataWareHouse dw, bool rState)
        {
            dataWH = dw;
            runState = rState;
            HookManager.KeyDown += HookManager_KeyDown;
        }

        public RunClick(ref DataWareHouse dw, bool rState, int idxTaskTest)
        {
            dataWH = dw;
            runState = rState;
            idxTskTest = idxTaskTest;
            HookManager.KeyDown += HookManager_KeyDown;
        }

        public RunClick()
        {
            HookManager.KeyDown += HookManager_KeyDown;
        }

        public bool RunState
        {
            get
            {
                return runState;
            }
            set
            {
                runState = value;
            }
        }

        public bool RefreshImage
        {
            get
            {
                return refreshImage;
            }
            set
            {
                refreshImage = value;
            }
        }

        private const Int32 MOUSEEVENTF_LEFTDOWN = 0x0002;
        private const Int32 MOUSEEVENTF_LEFTUP = 0x0004;
        private const Int32 MOUSEEVENTF_WHEEL = 0x0800;
        private const Int32 WHEEL_DELTA = 120;
        //private const UInt32 MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        //private const UInt32 MOUSEEVENTF_MIDDLEUP = 0x0040;
        [DllImport("user32.dll")] 
        private static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, IntPtr dwExtraInfo);

        [DllImport("user32.dll")]
        private static extern bool SetCursorPos(Int32 X, Int32 Y);

        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();

        [DllImport("user32.dll")]
        static extern IntPtr GetWindowDC(IntPtr ptr);

        [DllImport("gdi32.dll")]
        static extern COLORRGBA GetPixel(IntPtr hdc, int x, int y);

        [DllImport("user32.dll")]
        static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);

        public Color GetColorAtMouseClick()
        {
            IntPtr deskWnd = GetDesktopWindow();

            IntPtr deskHDC = GetWindowDC(deskWnd);

            COLORRGBA c = GetPixel(deskHDC, Cursor.Position.X, Cursor.Position.Y);

            ReleaseDC(deskWnd, deskHDC);
            return Color.FromArgb(c.a, c.r, c.g, c.b);
        }

        public Color GetColorAtMouseClick(int X, int Y)
        {
            IntPtr deskWnd = GetDesktopWindow();

            IntPtr deskHDC = GetWindowDC(deskWnd);

            COLORRGBA c = GetPixel(deskHDC, X, Y);

            ReleaseDC(deskWnd, deskHDC);
            return Color.FromArgb(c.a, c.r, c.g, c.b);
        }

        public static void SendClick(Point location)
        {
            //Cursor.Position = location;
            SetCursorPos(location.X, location.Y);
            Thread.Sleep(2);
            mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new IntPtr());
            Thread.Sleep(2);
            mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new IntPtr());
            Thread.Sleep(2);
        }

        public static void SendWheel(int direction_interval)
        {
            mouse_event(MOUSEEVENTF_WHEEL, 0, 0, direction_interval*WHEEL_DELTA, new IntPtr());
        }

        private void HookManager_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
                runState = false;
            if (e.KeyCode == Keys.Space)
                refreshImage = false;
            if (e.KeyCode == Keys.Pause)
                isPause = true;
            if (e.KeyCode == Keys.P)
                isStop = true;
            if (e.KeyCode == Keys.C)
                isStop = false;
        } 

        public void RunTasks()
        {
            try
            {
                int runNumber = int.Parse(dataWH.RUNNUMBER);
                bool votan = false;
                if (runNumber == VOTAN) votan = true;
                dataWH.OpenLog();
                while (runState && (runNumber > 0 || votan))
                {
                    for (int i = 0; i < dataWH.LST_TSKLVL4.Count; i++)
                    {
                        if (i == dataWH.TASKLOGININDEX)
                            RunDangNhap(i);
                        else
                            RunTaskLevel4((TaskLevel4)dataWH.LST_TSKLVL4[i]);
                    }
                    if (!votan)
                        runNumber--;
                }
                dataWH.CloseLog();
                MessageBox.Show("Hoàn thành");
                runState = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTasks" + ex.Message);
            }
        }

        public void RunTaskTest()
        {
            try
            {
                if (idxTskTest == dataWH.TASKLOGININDEX)
                    RunDangNhap(idxTskTest);
                else
                    RunTaskLevel4((TaskLevel4)dataWH.LST_TSKLVL4[idxTskTest]);
                MessageBox.Show("Hoàn thành test");
                runState = false;
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTaskTest" + ex.Message);
            }
        }

        private void RunTaskLevel4(TaskLevel4 tskLvl4)
        {
            try
            {
                int count = tskLvl4.arrTskLvl3_count;
                bool isNormal = tskLvl4.isNormal;
                bool atTimeFlag = false;
                if (!isNormal)
                {
                    count = 1;
                    if (tskLvl4.arrTskLvl3_Count.Contains(','))
                        specialTask = tskLvl4;
                    else
                    {
                        specialTaskAtTime = tskLvl4;
                        atTimeFlag = true;
                    }
                    beginEstimate = DateTime.Now;
                }

                if (!atTimeFlag)
                {
                    while (runState && count > 0)
                    {
                        dataWH.WriteLog(tskLvl4.name);
                        foreach (TaskLevel3 tskLvl3 in tskLvl4.arrTskLvl3)
                        {
                            RunTaskLevel3(tskLvl3);
                        }
                        count--;
                    }
                }

                if (!isNormal)
                {
                    isHaveSpecialTask = true;
                    string[] strSplit = tskLvl4.arrTskLvl3_Count.Split(',');
                    if (strSplit.Length > 1)
                    {
                        minuteST = int.Parse(strSplit[0]);
                        percentST = int.Parse(strSplit[1]);
                        midCheckST = bool.Parse(strSplit[2]);

                        excutiveTime = DateTime.Now - beginEstimate;
                        if (midCheckST)
                        {
                            int midMinute = minuteST / 2 - minuteST * percentST / 100;
                            midTimeST = DateTime.Now;
                            midTimeST = midTimeST.Add(new TimeSpan(0, (int)(midMinute + excutiveTime.TotalMinutes), 0));
                            midTimeCheckST = true;
                        }
                        endTimeST = DateTime.Now;
                        endTimeST = endTimeST.Add(new TimeSpan(0, (int)(minuteST + excutiveTime.TotalMinutes), 0));
                        endTimeCheckST = true;
                    }
                    else
                    {
                        strSplit = tskLvl4.arrTskLvl3_Count.Split(':');
                        atTime = new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,
                                                int.Parse(strSplit[0]),int.Parse(strSplit[1]),0);
                        atTimeCheckST = true;
                    }
                    
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTaskLevel4" + ex.Message);
            }
        }

        private void RunTaskLevel3(TaskLevel3 tskLvl3)
        {
            try
            {
                int count = tskLvl3.arrTskLvl2_count;
                TimeSpan interval;
                while (runState && count > 0)
                {
                    foreach (TaskLevel2 tskLvl2 in tskLvl3.arrTskLvl2)
                    {
                        RunTaskLevel2(tskLvl2);

                        if (!isHaveSpecialTask) continue;

                        #region Special task
                        //check special task
                        if (midTimeCheckST)
                        {
                            interval = DateTime.Now - midTimeST;
                            if (interval.TotalMinutes >= 0)
                            {
                                //RunTaskLevel4(specialTask);
                                midTimeCheckST = false;
                                foreach (TaskLevel3 tskLvl3i in specialTask.arrTskLvl3)
                                {
                                    RunTaskLevel3(tskLvl3i);
                                }
                            }
                        }

                        if (endTimeCheckST)
                        {
                            interval = DateTime.Now - endTimeST;
                            if (interval.TotalMinutes >= 0)
                            {

                                isHaveSpecialTask = false;
                                dataWH.WriteLog(specialTask.name);
                                foreach (TaskLevel3 tskLvl3i in specialTask.arrTskLvl3)
                                {
                                    RunTaskLevel3(tskLvl3i);
                                }

                                isHaveSpecialTask = true;
                                endTimeST = DateTime.Now.Add(new TimeSpan(0, (int)(minuteST + excutiveTime.TotalMinutes), 0));

                                if (midCheckST)
                                {
                                    int midMinute = minuteST / 2 - minuteST * percentST / 100;
                                    midTimeST = DateTime.Now;
                                    midTimeST = midTimeST.Add(new TimeSpan(0, (int)(midMinute + excutiveTime.TotalMinutes), 0));
                                    midTimeCheckST = true;
                                }
                            }
                        }

                        if (atTimeCheckST)
                        {
                            interval = DateTime.Now - atTime;
                            if (interval.TotalMinutes >= 0)
                            {
                                if (interval.TotalMinutes <= 60)
                                {
                                    isHaveSpecialTask = false;

                                    foreach (TaskLevel3 tskLvl3i in specialTaskAtTime.arrTskLvl3)
                                    {
                                        RunTaskLevel3(tskLvl3i);
                                    }

                                    isHaveSpecialTask = true;
                                }

                                atTime = atTime.AddDays(1);
                            }
                        }
                        #endregion
                    }
                    count--;                    
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTaskLevel3" + ex.Message);
            }
        }

        private void RunTaskLevel2(TaskLevel2 tskLvl2)
        {
            try
            {
                int count = tskLvl2.arrTskLvl1_count;
                while (runState && count > 0)
                {
                    foreach (TaskLevel1 tskLvl1 in tskLvl2.arrTskLvl1)
                    {
                        RunTaskLevel1(tskLvl1);
                        if (taskPass)
                        {
                            taskPass = false;
                            break;
                        }
                    }
                    count--;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTaskLevel2" + ex.Message);
            }
        }

        private void RunTaskLevel1(TaskLevel1 tskLvl1)
        {
            try
            {
                if (!runState) return;
                if (isPause)
                {
                    Thread.Sleep(10000);
                    isPause = false;
                }
                
                while (isStop)
                    Thread.Sleep(200);

                int nClickOffsetNumber = tskLvl1.clickOffsetNumber;
                int nClickNumber = tskLvl1.clickNumber;
                int clickInterval = tskLvl1.clickInterval;
                int clickOffset = tskLvl1.clickOffset;
                

                DataRow rd = dataWH.DT.Rows.Find(tskLvl1.PosName);                
                Point posCode = new Point();
                posCode.X = (int)rd["X_Code"];
                posCode.Y = (int)rd["Y_X"];

                switch (posCode.X)
                {
                    case WAITCODE:
                        Thread.Sleep(posCode.Y);
                        break;
                    case WHEELCODE:
                        SendWheel(posCode.Y);
                        break;
                    case COLORCODE:
                        //Point curPos = Cursor.Position;                        
                        if (GetColorAtMouseClick() == Color.FromArgb((int)rd["A"], (int)rd["R"], (int)rd["G"], (int)rd["B"]))
                        {
                            taskPass = true;
                        }
                        break;
                    case CLICKCOLORCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        for (int i = -1; i < nClickOffsetNumber; i++)
                        {
                            for (int j = 0; j < nClickNumber; j++)
                            {
                                int A = (int)rd["A"];
                                int R = (int)rd["R"];
                                int G = (int)rd["G"];
                                int B = (int)rd["B"];
                                //Color clr2 = Color.FromArgb((int)rd["A"], (int)rd["R"], (int)rd["G"], (int)rd["B"]);
                                Color clr1 = GetColorAtMouseClick(posCode.X, posCode.Y);

                                if ((A < 0 || clr1.A == A) && (R < 0 || clr1.R == R) && (G < 0 || clr1.G == G) && (B < 0 || clr1.B == B))
                                    SendClick(posCode);
                                else
                                    return;
                                Thread.Sleep(clickInterval);
                            }
                            posCode.X += clickOffset;
                        }
                        break;
                    case UNCLICKCOLORCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        for (int i = -1; i < nClickOffsetNumber; i++)
                        {
                            for (int j = 0; j < nClickNumber; j++)
                            {
                                int A = (int)rd["A"];
                                int R = (int)rd["R"];
                                int G = (int)rd["G"];
                                int B = (int)rd["B"];
                                //Color clr2 = Color.FromArgb((int)rd["A"], (int)rd["R"], (int)rd["G"], (int)rd["B"]);
                                Color clr1 = GetColorAtMouseClick(posCode.X, posCode.Y);
                                //if (clr1.R == 0 && clr1.G == 0 && clr1.B == 0) //black is don't do
                                //    continue;

                                if ((A<0 || clr1.A == A) && (R<0 || clr1.R == R) && (G<0 || clr1.G == G) && (B<0 || clr1.B == B))
                                    return;
                                else
                                    SendClick(posCode);
                                Thread.Sleep(clickInterval);
                            }
                            posCode.X += clickOffset;
                        }
                        break;
                    case UNCLICKBLACKLISTCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        for (int i = -1; i < nClickOffsetNumber; i++)
                        {
                            for (int j = 0; j < nClickNumber; j++)
                            {                                
                                Color clr1 = GetColorAtMouseClick(posCode.X, posCode.Y);
                                string keyClr = clr1.A.ToString() + "," + clr1.R.ToString() + "," + clr1.G.ToString() + "," + clr1.B.ToString();
                                if (dataWH.BLACKLISTHASH.ContainsKey(keyClr))
                                    continue;
                                else
                                    SendClick(posCode);
                                Thread.Sleep(clickInterval);
                            }
                            posCode.X += clickOffset;
                        }
                        break;
                    case CLICKWHITELISTCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        for (int i = -1; i < nClickOffsetNumber; i++)
                        {
                            for (int j = 0; j < nClickNumber; j++)
                            {
                                Color clr1 = GetColorAtMouseClick(posCode.X, posCode.Y);
                                string keyClr = clr1.A.ToString() + "," + clr1.R.ToString() + "," + clr1.G.ToString() + "," + clr1.B.ToString();
                                if (dataWH.WHITELISTHASH.ContainsKey(keyClr))
                                    SendClick(posCode);
                                else
                                    continue;                                    
                                Thread.Sleep(clickInterval);
                            }
                            posCode.X += clickOffset;
                        }
                        break;
                    case CLICKANDPASTELINKCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        SendClick(posCode);
                        Thread.Sleep(clickInterval);
                        SendKeys.SendWait((string)rd["link"]);
                        Thread.Sleep(clickInterval);
                        break;
                    case CLICKANDPASTEANDENTERLINKCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        SendClick(posCode);
                        Thread.Sleep(clickInterval);
                        SendKeys.SendWait((string)rd["link"]);
                        Thread.Sleep(clickInterval);
                        SendKeys.SendWait("{ENTER}");
                        Thread.Sleep(clickInterval);
                        break;
                    case CLICKANDPASTEANDTABLINKCODE:
                        posCode.X = (int)rd["Y_X"];
                        posCode.Y = (int)rd["Y"];
                        SendClick(posCode);
                        Thread.Sleep(clickInterval);
                        SendKeys.SendWait((string)rd["link"]);
                        Thread.Sleep(clickInterval);
                        SendKeys.SendWait("{TAB}");
                        Thread.Sleep(clickInterval);
                        break;
                    default:                                             
                        for (int i = -1; i < nClickOffsetNumber; i++)
                        {
                            for (int j = 0; j < nClickNumber; j++)
                            {
                                SendClick(posCode);
                                Thread.Sleep(clickInterval);
                            }
                            posCode.X += clickOffset;
                        }
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunTaskLevel1" + ex.Message);
            }
        }

        private void RunDangNhap(int idx)
        {
            try
            {
                do
                {
                    //open web link
                    int countTry = 0;
                    do
                    {
                        countTry++;
                        if (countTry == 10)
                        {
                            Thread.Sleep(600000);
                            countTry = 0;
                        }
                        //close windows
                        SendClick(new Point(1340, 6));
                        Thread.Sleep(2000);
                        //open windows
                        TaskLogin tskLogin = (TaskLogin)dataWH.GetTaskLogin(idx);
                        System.Diagnostics.Process.Start(tskLogin.webAddress);
                        Thread.Sleep(4000);
                        SendClick(GetPosition(dataWH.TSKLOGIN.logout_Pos));
                        Thread.Sleep(1000);
                    }
                    while (runState && (GetColorAtMouseClick() == Color.FromArgb(0, 255, 255, 255) || GetColorAtMouseClick() == Color.FromArgb(0, 0, 0, 0)));

                    //Logout
                    Point curCursor = GetPosition(dataWH.TSKLOGIN.logout_Pos);
                    SendClick(curCursor);

                    //Login
                    Thread.Sleep(2000);
                    curCursor = GetPosition(dataWH.TSKLOGIN.usrName_Pos);
                    SendClick(curCursor);
                    Thread.Sleep(100);
                    SendKeys.SendWait(dataWH.TSKLOGIN.usrName);
                    SendKeys.SendWait("{TAB}");
                    SendKeys.SendWait(dataWH.TSKLOGIN.pass);
                    SendClick(GetPosition(dataWH.TSKLOGIN.login_Pos));
                    Thread.Sleep(20000);
                }
                while (runState && GetColorAtMouseClick() == Color.FromArgb(0, 255, 255, 255));
            }
            catch (Exception ex)
            {
                MessageBox.Show("RunDangNhap " + ex.Message);
            }
        }

        private Point GetPosition(string name)
        {
            //Datarow idx = dataWH.DT.Rows.Find(name);
            Point pos = new Point();
            //string dataPos = (string)dataWH.DT.Rows.Find(name)[1];

            //string[] dataPosXY = dataPos.Split(',');

            //pos.X = int.Parse(dataPosXY[0]);
            //pos.Y = int.Parse(dataPosXY[1]);
            DataRow dr = dataWH.DT.Rows.Find(name);
            pos.X = (int)dr["X_Code"];
            pos.Y = (int)dr["Y_X"];
            return pos;
        }
    }
}
